﻿/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.BluetoothChat;

import java.io.BufferedOutputStream;

import java.util.concurrent.Semaphore;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager.WakeLock;
import android.provider.MediaStore.Images;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
//import android.graphics.ImageFormat;//这是android 2.2支持的！！！

/**
 * This is the main Activity that displays the current chat session.
 */
public class BluetoothChat extends Activity {
    // Debugging
    private static final String TAG = "BluetoothChat";
    private static final boolean D = true;
    int debugsum = 0;

    private static final boolean use_Mac = true;
    private static final boolean isTaken = false;
    // Message types sent from the BluetoothChatService Handler
    public static final int MESSAGE_STATE_CHANGE = 1;
    public static final int MESSAGE_READ = 2;
    public static final int MESSAGE_WRITE = 3;
    public static final int MESSAGE_DEVICE_NAME = 4;
    public static final int MESSAGE_TOAST = 5;

    // Key names received from the BluetoothChatService Handler
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";
    //byte[] sendbuffer = new byte[1024*1024*3];
    //byte[] sendbuffer = new byte[115200];
    byte[] sendbuffer = new byte[460800]; //640*480*1.5 = 460800B,即是最大的preview的YUV420SP数据的大小
    private Semaphore sendbufferlock = new Semaphore(1);
    
    byte[] psendbuffer =null;
    int datesendlength = 0;
    UDPClient sendthread = null;
    int previewwidth = 0;
    int previewheight = 0;
    

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE = 1;
    private static final int REQUEST_ENABLE_BT = 2;

    // Layout Views
    private TextView mTitle;
    private ListView mConversationView; //显示通信信息的控件

    //机器人行为控制按钮定义
    private Button mButton1;
    private Button mButton2;
    private Button mButton3;
    private Button mButton4;
    private Button mButton5;
    private Button mButton6;
    private Button mButton7;
    private Button mButton8;
    private Button mButtonStart;
    
    //按钮的时间监听对象
    MyButtonListener mButtonListener;
    
    private boolean isStart =false;
    
    //显示预览和处理预览的控件，相机设备对象
	private SurfaceView mSurfaceView;
	private SurfaceHolder mSfHolder;
	private Camera mCamera = null;
	Bitmap mBitmap = null;
    
	//注意回调对象PictureCallback的作用，在拍照时被调用，用于拍照后读取Camera中的图像数据，然后保存
	private Camera.PictureCallback  pictureCallback=null ;
	private Camera.PreviewCallback  previewCallback=null; 
    
    // Name of the connected device
    private String mConnectedDeviceName = null;
    // Array adapter for the conversation thread
    private ArrayAdapter<String> mConversationArrayAdapter;
    // String buffer for outgoing messages
    private StringBuffer mOutStringBuffer;
    // Local Bluetooth adapter
    private BluetoothAdapter mBluetoothAdapter = null;
    // Member object for the chat services
    private BluetoothChatService mChatService = null;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(D) Log.e(TAG, "+++ ON CREATE +++");
        
        Log.i("cyy","onCreat....");

        // Set up the window layout
        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        setContentView(R.layout.main);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);    
        
    	File file = new File("/sdcard/RobotController");
    	RandomAccessFile debugfile ;
        if (!file.exists())
			try {
				file.createNewFile();
			    debugfile = new RandomAccessFile(file, "rw");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
        
        
         // Set up the custom title
         mTitle = (TextView) findViewById(R.id.title_left_text);
         mTitle.setText(R.string.app_name);
         mTitle = (TextView) findViewById(R.id.title_right_text);

        //机器人行为控制按钮。。。设置长按的事件监听
       mButton1 = (Button)findViewById(R.id.button1);
       mButton2 = (Button)findViewById(R.id.button2);
       mButton3 = (Button)findViewById(R.id.button3);
       mButton4 = (Button)findViewById(R.id.button4);
       mButton5 = (Button)findViewById(R.id.button5);
       mButton6 = (Button)findViewById(R.id.button6);
       mButton7 = (Button)findViewById(R.id.button7);
       mButton8 = (Button)findViewById(R.id.button8);
       mButtonStart = (Button)findViewById(R.id.buttonStart);
       
       mButtonListener = new MyButtonListener();
       
       mButton1.setOnLongClickListener(mButtonListener);
       mButton2.setOnLongClickListener(mButtonListener);
       mButton3.setOnLongClickListener(mButtonListener);
       mButton4.setOnLongClickListener(mButtonListener);
       mButton5.setOnLongClickListener(mButtonListener);
       mButton6.setOnLongClickListener(mButtonListener);
       mButton7.setOnLongClickListener(mButtonListener);
       mButton8.setOnLongClickListener(mButtonListener);
       mButtonStart.setOnLongClickListener(mButtonListener);
               
        // Get local Bluetooth adapter
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
           
            finish();
            return;
        }
        
        
        //创建用于相机预览的回调对象
        pictureCallback = new Camera.PictureCallback() {
    		public void onPictureTaken(byte[] data, Camera camera) {
    			Log.i("cyy","onPictureTaken");
    			Toast.makeText(getApplicationContext(), "正在保存照片……datalength is"+data.length, Toast.LENGTH_LONG).show();
    			mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    			File file = new File("/sdcard/"+ new DateFormat().format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg");
    			try {
    				file.createNewFile();
    				Log.i("cyy","create file successed");
    				BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
    				mBitmap.compress(Bitmap.CompressFormat.PNG, 80, os);
    				
    				os.flush();
    				os.close();
    				Toast.makeText(getApplicationContext(), "图片保存完毕，在存储卡的根目录", Toast.LENGTH_LONG).show();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}	
    		}
    	};
    	
    	
    	//已经成功验证，该函数可以被正确调用，当前任务是增加网络模块！！！
    	//将date[]中数据赋值给另外一个数据，让另一个线程去发送！
    	//验证测试表明，发送UDP数据包的大小有限制，一次发送1KB！！！所以要测试UDP数据包的大小，否则丢失非常严重！！！
    	previewCallback = new Camera.PreviewCallback() {
			private int tick =0;
			private int numframe=0;
			boolean first = true;
			@Override
			public synchronized void onPreviewFrame(byte[] data, Camera camera) {
				//将data[]中的数据发送出去，data[]的数据是线程安全的，有同步机制
			    try {
			    	psendbuffer = data;
			    	datesendlength = data.length;
			    	//System.arraycopy(sendbuffer , 0 , data , 0 , data.length);
			    	
			    	//规定，各个线程互斥得访问sendbuffer
			    	sendbufferlock.acquire();
			    	System.arraycopy(data , 0 , sendbuffer , 0 , data.length);	
			    	sendbufferlock.release();
			    	
			    	sendthread.start();		
			    	/*改进计划，需要给sendbuffer上锁，否则发送的数据可能是乱的*/
			    	
			    	
			    	//终于发现了问题，，貌似是这个复制数组出现了错误，复制的是无效的空数据？？？？
			    	//原来是我把目的数据和源数据弄反了，复制数据全是0
		
			     	Toast.makeText(getApplicationContext(), "onPreView datalenth is "+data.length , Toast.LENGTH_LONG).show(); 

			    	//截取一帧YUV数据存储在本地，用来验证YUV420SP转RGB24或RGB32的算法
			        /*
			    	File file = new File("/sdcard/pal.yuv");
			        if (!file.exists())
			         file.createNewFile();
			         RandomAccessFile raf = new RandomAccessFile(file, "rw");
			         raf.write(data);
			         raf.close();
			         Toast.makeText(getApplicationContext(), "视频截取成功", Toast.LENGTH_LONG).show();
			        */
			    	
			       } catch (Exception ex) {
			       Log.v("System.out", ex.toString());
			       }//endtry

			}//endonPriview
		};
 	
        //设置预览控件
        mSurfaceView = (SurfaceView)this.findViewById(R.id.SurfaceView01); 
        mSfHolder = mSurfaceView.getHolder();
        
        mSfHolder.addCallback(new SurfaceHolder.Callback() {
			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				Log.i("camer","SurfaceHolder.Callback....surfaceDestroyed");
				Toast.makeText(getApplicationContext(), "surfaceDestroyed", Toast.LENGTH_LONG).show();
				mCamera.stopPreview();
				mCamera.release();
				mCamera = null;
			}
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				//当预览视图创建的时候开启相机
				mCamera = Camera.open();
				try {
					Log.i("camer","SurfaceHolder.Callback....surfaceCreated");
					Toast.makeText(getApplicationContext(), "surfaceCreated", Toast.LENGTH_LONG).show();
					//mCamera.setDisplayOrientation();
					//设置预览
					mCamera.setPreviewDisplay(holder);
					 sendthread = new UDPClient();
					//sendthread.start();//改到onPreveiw去!
				} catch (IOException e) {
					// 释放相机资源并置空
					mCamera.release();
					mCamera = null;
				}
			}
			
			//当surface视图数据发生变化时，处理预览信息
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
				//相机的参数是否设置有效，可以查看在DDMS中查看Log.i得知！！！
				Log.i("camer","SurfaceHolder.Callback....surfaceChanged");
				Toast.makeText(getApplicationContext(), "surfaceChanged", Toast.LENGTH_LONG).show();
				Camera.Parameters parameters = mCamera.getParameters();
				parameters.setPictureFormat(PixelFormat.JPEG);
				
				//获取caera支持的PictrueSize，看看能否设置？？
				List<Size> pictureSizes = mCamera.getParameters().getSupportedPictureSizes();
				List<Size> previewSizes = mCamera.getParameters().getSupportedPreviewSizes();
				List<Integer> previewFormats = mCamera.getParameters().getSupportedPreviewFormats();
				List<Integer> previewFrameRates = mCamera.getParameters().getSupportedPreviewFrameRates();
				Log.i("camer","cyy support parameters is ");
					
				Size psize = null;
				for(int i=0 ; i<pictureSizes.size() ; i++)
				{
				   psize = pictureSizes.get(i);
				   Log.i("camer","cyy PictrueSize,width: "+psize.width+" height"+psize.height);
				}
				for(int i=0 ; i<previewSizes.size() ; i++)
				{
				   psize = previewSizes.get(i);
				   Log.i("camer","cyy PreviewSize,width: "+psize.width+" height"+psize.height);
				}
				Integer pf = null;
				for(int i=0 ; i<previewFormats.size() ; i++)
				{
					pf = previewFormats.get(i);
					Log.i("camer","cyy previewformates:"+pf);
				}
				
				/*  //导致异常，不知道为什么。。
				for(int i=0 ; i<previewFrameRates.size() ; i++)
				{
					  pf = previewFrameRates .get(0);
					  Log.i("camer","cyy previewFrameRates:"+pf);
				}*/
				
				
				
				//终于修改成功，根据Log.i()打印的信息，得知系统支持的各种参数，从而再设置！
				parameters.setPictureSize(640, 480);
				
     			parameters.setPreviewSize(320 , 240);  //设置成功
				//parameters.setPreviewSize(176 , 144); 
				
     			//parameters.setRotation(90);          //导致程序崩溃。
				//parameters.setPreviewFrameRate(15);    //没有修改成功。
	            parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);  

				mCamera.setPreviewCallback(previewCallback);
				mCamera.setParameters(parameters);	
				mCamera.startPreview();
				
				Camera.Size csize = mCamera.getParameters().getPreviewSize ();
				previewheight = csize.height;
				previewwidth = csize.width;
				
				Log.i("cyy", "cyy ,after setting, previewSize:width: "+csize.width+" height: "+csize.height);
				csize = mCamera.getParameters().getPictureSize();
				Log.i("cyy", "cyy ,after setting, pictruesize:width: "+csize.width+" height: "+csize.height);
			    Log.i("cyy", "cyy ,after setting, previewformate is "+mCamera.getParameters().getPreviewFormat());
			    Log.i("cyy", "cyy ,after setting, previewframetate is "+mCamera.getParameters().getPreviewFrameRate());
				//终于设置成功了！！！
			}
		});//endofaddcallback
         
        mSfHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        
    
    }//endOncreat
    
    
	//按下相机键的处理函数，关键是拍照
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		Log.i("cyy","MainActivity.onKeyDown");
		if(keyCode == KeyEvent.KEYCODE_CAMERA)
		{
			if(mCamera != null)
			{
				Log.i("cyy","mCamera.takePicture");
				//当按下相机按钮时，执行相机对象的takePicture()方法,该方法有三个回调对象做入参，不需要的时候可以设null
				//将图像数据从Camera对象读取到回调对象pictureCallack中
				mCamera.takePicture(null, null, pictureCallback);
				//能否设定定时器1秒内调用takePicture15次？也就是单独使用一个线程，每次tackPictrue之后休眠40毫秒？
				//效率如何？延迟大否？数据量应该会很小，而且压缩转换的效率肯定比我自己写的要高！！！
				return mSurfaceView.onKeyDown(keyCode, event);
			}
		
		}  	
    	//按下键盘上返回按钮
    	if(keyCode == KeyEvent.KEYCODE_BACK){
    		ExitOptionsDialog();
    		return true;
    	}else{		
    		return super.onKeyDown(keyCode, event);
    	}
    	
		
	}
    
    @Override
    public void onStart() {
        super.onStart();
        if(D) Log.e(TAG, "++ ON START ++");

        // If BT is not on, request that it be enabled.
        // setupChat() will then be called during onActivityResult
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        // Otherwise, setup the chat session
        } else {
            if (mChatService == null) setupChat();
        }
    }

    @Override
    public synchronized void onResume() {
        super.onResume();
        if(D) Log.e(TAG, "+ ON RESUME +");

        // Performing this check in onResume() covers the case in which BT was
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mChatService != null) {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
              // Start the Bluetooth chat services
              mChatService.start();
            }
        }
    }
    
    private class MyButtonListener implements OnLongClickListener{
		@Override
		public boolean onLongClick(View v) {
			//TODO Auto-generated method stub
			//mTextMainState.setText("long click on button___");
			if(mChatService.getState() == BluetoothChatService.STATE_CONNECTED)
	      {
			String message = null;
			switch( v.getId() )
			{
				case R.id.button1:
					message = "1";
				break;
				case R.id.button2:
					message = "2";
				break;
				case R.id.button3:
					message = "3";
				break;
				case R.id.button4:
					message = "4";
				break;
				case R.id.button5:
					message = "5";
				break;
				case R.id.button6:
					message = "6";
				break;				
				case R.id.button7:
					message = "7";
				break;
				case R.id.button8:
					message = "8";
					break;	
				case R.id.buttonStart:
				{
					   if(isStart)
					   {
						  isStart = false;
						  message = "stop";
						  mButtonStart.setText("START");
					   }else
					   {
						  isStart = true;
						  message = "start";
						  mButtonStart.setText("STOP");
					   }
				    break;
				}
					}
			 if(isStart)
			 {
				 sendMessage(message);
			 }	
	      }//endif
			
			return false;
		}
    	
    }
    
    private void setupChat() {
        Log.d(TAG, "setupChat()");

        //显示蓝牙通信内容的控件
        // Initialize the array adapter for the conversation thread
        mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
        mConversationView = (ListView) findViewById(R.id.Mesgview);
        mConversationView.setAdapter(mConversationArrayAdapter);
        
        // Initialize the BluetoothChatService to perform bluetooth connections
        mChatService = new BluetoothChatService(this, mHandler);

        // Initialize the buffer for outgoing messages
        mOutStringBuffer = new StringBuffer("");
    }

    @Override
    public synchronized void onPause() {
        super.onPause();
        if(D) Log.e(TAG, "- ON PAUSE -");
    }

    @Override
    public void onStop() {
        super.onStop();
        if(D) Log.e(TAG, "-- ON STOP --");
        
        Toast.makeText(this, "senddate number is "+debugsum, Toast.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Stop the Bluetooth chat services
        if (mChatService != null) mChatService.stop();
        if(D) Log.e(TAG, "--- ON DESTROY ---");
    }

    private void ensureDiscoverable() {
        if(D) Log.d(TAG, "ensure discoverable");
        if (mBluetoothAdapter.getScanMode() !=
            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }
    }

    /**
     * Sends a message.
     * @param message  A string of text to send.
     */
    private void sendMessage(String message) {
        // Check that we're actually connected before trying anything
        if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
            Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        // Check that there's actually something to send
        if (message.length() > 0) {
            // Get the message bytes and tell the BluetoothChatService to write
            byte[] send = message.getBytes();
            mChatService.write(send);

            // Reset out string buffer to zero 
            mOutStringBuffer.setLength(0);
        }
    }


    // The Handler that gets information back from the BluetoothChatService
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_STATE_CHANGE:
                if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
                switch (msg.arg1) {
                case BluetoothChatService.STATE_CONNECTED:
                    mTitle.setText(R.string.title_connected_to);
                    mTitle.append(mConnectedDeviceName);
                    mConversationArrayAdapter.clear();
                    break;
                case BluetoothChatService.STATE_CONNECTING:
                    mTitle.setText(R.string.title_connecting);
                    break;
                case BluetoothChatService.STATE_LISTEN:
                case BluetoothChatService.STATE_NONE:
                    mTitle.setText(R.string.title_not_connected);
                    break;
                }
                break;
            case MESSAGE_WRITE:
                byte[] writeBuf = (byte[]) msg.obj;
                // construct a string from the buffer
                String writeMessage = new String(writeBuf);
                mConversationArrayAdapter.add("Me:  " + writeMessage);
                break;
            case MESSAGE_READ:
                byte[] readBuf = (byte[]) msg.obj;
                // construct a string from the valid bytes in the buffer
                String readMessage = new String(readBuf, 0, msg.arg1);
                mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);
                break;
            case MESSAGE_DEVICE_NAME:
                // save the connected device's name
                mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
                Toast.makeText(getApplicationContext(), "Connected to "
                               + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_TOAST:
                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
                               Toast.LENGTH_SHORT).show();
                break;
            }
        }
    };

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(D) Log.d(TAG, "onActivityResult " + resultCode);
        switch (requestCode) {
        case REQUEST_CONNECT_DEVICE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                // Get the device MAC address
                String address = data.getExtras()
                                     .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
                // Get the BLuetoothDevice object
                BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
                // Attempt to connect to the device
                mChatService.connect(device);
            }
            break;
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
                setupChat();
            } else {
                // User did not enable Bluetooth or an error occured
                Log.d(TAG, "BT not enabled");
                Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }
  //退出软件的时候确认选择      	
    private void ExitOptionsDialog()
    {
    	  AlertDialog.Builder builder = new AlertDialog.Builder(this); 
    	  builder.setMessage("是否退出程序") 
    	         .setCancelable(false) 
    	         .setPositiveButton("确定", new DialogInterface.OnClickListener() { 
    	             public void onClick(DialogInterface dialog, int id) { 
    	            	 android.os.Process.killProcess(android.os.Process.myPid());
    	             } 
    	         }) 
    	         .setNegativeButton("取消", new DialogInterface.OnClickListener() { 
    	             public void onClick(DialogInterface dialog, int id) { 
    	                  dialog.cancel(); 
    	             } 
    	         }); 
    	  AlertDialog alert = builder.create();
    	  alert.show();
    }

    
//创建menu按键菜单
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.option_menu, menu);
        return true;
    }
    
//menu按键菜单的选择函数
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.scan:
            // Launch the DeviceListActivity to see devices and do scan
            Intent serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
            return true;
        case R.id.discoverable:
            // Ensure this device is discoverable by others
        	Toast.makeText(this, "senddate number is "+debugsum, Toast.LENGTH_LONG).show();
           // ensureDiscoverable();
            return true;
        }
        return false;
    }
    
    
   class UDPClient extends Thread
   {
	   public void run()
	   {
		   try {
		       
			   Log.i("cyy","cyy udpclient thread....");
			   
			   
			   
			   //进过多次测试，数据完全发送出去了。但是使用UDP发送，需要解决的技术难题太多！！
			   //需要给报文添加序号，缓存发送。
			   /*			   
			   DatagramSocket socket = new DatagramSocket();	 
	           InetAddress serverAddress = InetAddress.getByName("192.168.0.10");

	           String str = "hello,android,internet,from UDPClient Thread!, datalenth is " + datesendlength;
	        	  int total = datesendlength;
	        	  int i=0;
	        	  int sum=0;//for debug
	        	  byte[] tempbuffer = new byte[1024];
	        	  DatagramPacket packet;
	        	  while(total > 0)
	        	  {	        		  
	        		  if(total<1024)//此时是最后一个包，可能小于1024
	        		  {
	        		  //改进，可以不必再复制数组，DatagramPacket可以指定数组特定部分的数据,offset
	        			  System.arraycopy(tempbuffer , 0, sendbuffer , datesendlength-datesendlength%1024 , datesendlength%1024);
	        			  packet = new DatagramPacket(tempbuffer ,datesendlength%1024, serverAddress , 5555 );  
	        			  //sum = sum+datesendlength%1024;//fordebgu
	        		  }    			               
	        		  else
	        		  {   
	        			  System.arraycopy(tempbuffer , 0, sendbuffer , 1024*i , 1024);
	        			  packet = new DatagramPacket(tempbuffer ,1024 , serverAddress , 5555 );  
	        			 // sum = sum+1024;
	        		  }	        		  
	        		  socket.send(packet);
	        		  sleep(10);//可以全部接受，但是数据量太大！！！
	        		  sum = sum+packet.getLength();//fordebug
	        		  i++;
	        		  total = total - 1024;   		  
	        	  }
	        	  debugsum = sum;//fordebug
	        	  Log.i("cyy","cyy udpclient thread ,the rest is "+ total + " the sum of senddate is "+sum);
                  */	           
			   
			   
			   
			   //尝试使用TCP编程，客户端完全地接受了数据，socket方案一
			   /*
			   long length = 0;
			   Socket clientsocket = new Socket("192.168.0.12" , 5555);
			   OutputStream dout = clientsocket.getOutputStream();
			   while(true)
			   {
			      dout.write(sendbuffer, 0, datesendlength);
			      Thread.sleep(50);
			   }
			   */
			   
			   
			   /*sockent方案二
			    * 
			    */
			 			   
			   Socket clientsocket = new Socket("192.168.0.12" , 5555);
			   DataOutputStream dos = new DataOutputStream(clientsocket.getOutputStream());
			   DataInputStream dis = new DataInputStream(clientsocket.getInputStream());			  
			   int tt= 432;  //5760 //28800	//一次发送432B，比较理想，这个数据非常关键，需要结合具体网络环境设置
			   int sendlength = 0;
			   int sum = 0;
			   
			   while(true)
			   {
				   
				   //互斥访问缓冲区
				   sendbufferlock.acquire();		
				   /*
				   for(int i = 0; i < datesendlength / tt; i++)				   
				   {
					   dos.write(sendbuffer, i * tt, tt);					  
				   }
				   */
				   
				   //在局域网下测试，效果还好，如果是177*144的分辨率，视频帧率能达到30F/s，非常流畅
				   //如果是320*240，视频帧率能达到10F/s，稍微有些延迟
				   //还可以继续改进。将sendbuffer设置更大些，或许速度会更大些。
				   //目前的极限速度为1MB/S，54Mbps的无线局域网应该能满足条件
				   //效果非常好，sendbuffer是一个阻塞函数，阻塞直到发完该缓冲区
				   //下一步计划，将sendbuffer设置更大些，将YUV转换成JPEG格式发送
				   //要考虑网络中断等情况，抛出异常等
				   dos.write(sendbuffer , 0 , datesendlength);				   
				   
				   sendbufferlock.release();			   
				   
				   //dos.write(sendbuffer);
				     dis.readBoolean();
				     //Thread.sleep(10);//现场的休眠时间可以自由调节
			   }
              			  
			   
			   
			   
			   //看能能否直接在这里调用这个函数，可以调用
			   /*
			   for(int i=0; i<10 ; i++)
			   { 
				   mCamera.takePicture(null, null, pictureCallback);
				   sleep(100);
			   }
			   */
			   
			   
			   /*先看看是否能压缩显示！！在本地能压缩成功，并且正确显示。
			    * 如果压缩的时间比较短，也可以直接发送jpeg图片过去。
			    * 可以将压缩时间计算出来，
			    */
			   /*
			   Bitmap bm = null;			   
			   int[] rgbBuff = new int[previewwidth * previewheight];
			   new DateFormat();
			   FileOutputStream out = new FileOutputStream("/sdcard/"+ DateFormat.format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg");
			   decodeYUV420SP_int(rgbBuff , sendbuffer , previewwidth , previewheight );
			   bm = Bitmap.createBitmap(rgbBuff, previewwidth, previewheight , Bitmap.Config.ARGB_8888);
			   bm.compress(Bitmap.CompressFormat.JPEG, 100, out);//调整到80，,70，照片变形了,90依然有水波纹？？？
		                                                        //调整到100则没有水波纹
			   out.close();
			   Log.i("cyy","cyy... pictrue capture succssed");		   
               */
			   
			   
			   
			   
	         } catch (Exception e) {
	           // TODO Auto-generated catch block
	           e.printStackTrace();
	        }//endtry
	         
	         
		    }//endrun
		   
   }//endclssDUPclient
   
   
   /*
    * YUV420SP转换成RGB24格式
    */
   private static void decodeYUV420SP_byte(byte[] rgbBuf, byte[] yuv420sp, int width, int height) 
   {
		   final int frameSize = width * height;
		   if (rgbBuf == null)
		   throw new NullPointerException("buffer 'rgbBuf' is null");
		   if (rgbBuf.length < frameSize * 3)
		   throw new IllegalArgumentException("buffer 'rgbBuf' size "
		   + rgbBuf.length + " < minimum " + frameSize * 3);

		   if (yuv420sp == null)
		   throw new NullPointerException("buffer 'yuv420sp' is null");

		   if (yuv420sp.length < frameSize * 3 / 2)
		   throw new IllegalArgumentException("buffer 'yuv420sp' size "
		   + yuv420sp.length + " < minimum " + frameSize * 3 / 2);

		   int i = 0, y = 0;
		   int uvp = 0, u = 0, v = 0;
		   int y1192 = 0, r = 0, g = 0, b = 0;

		   for (int j = 0, yp = 0; j < height; j++) 
		   {
		       uvp = frameSize + (j >> 1) * width;
		       u = 0;
		       v = 0;
		       
		       for(i = 0; i < width; i++, yp++) 
		      {
		            y=(0xff & ((int) yuv420sp[yp])) - 16;
		      
		         if(y < 0)
		            y = 0;
		         if((i & 1) == 0) 
		         {
		            v = (0xff & yuv420sp[uvp++]) - 128;
		            u = (0xff & yuv420sp[uvp++]) - 128;
		         }

		         y1192 = 1192 * y;
		         r = (y1192 + 1634 * v);
		         g = (y1192 - 833 * v - 400 * u);
		         b = (y1192 + 2066 * u);

		          if(r < 0)
		             r = 0;
		          else if (r > 262143)
		             r = 262143;
		   
		          if(g < 0)
		             g = 0;
		          else if (g > 262143)
		             g = 262143;
		   
	        	   if(b < 0)
		             b = 0;
		           else if (b > 262143)
		             b = 262143;

		          rgbBuf[yp * 3] = (byte) (r >> 10);
		          rgbBuf[yp * 3 + 1] = (byte) (g >> 10);
		          rgbBuf[yp * 3 + 2] = (byte) (b >> 10);
		       }//endfor
		   }//endfor
		
   }//endfunction
   
   
   /*
    * YUV420SP转换成RGB32格式
    */
   static public void decodeYUV420SP_int(int[] rgb, byte[] yuv420sp, int width, int height) {
       final int frameSize = width * height;

       for (int j = 0, yp = 0; j < height; j++) {
           int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
           for (int i = 0; i < width; i++, yp++) {
               int y = (0xff & ((int) yuv420sp[yp])) - 16;
               if (y < 0) y = 0;
               if ((i & 1) == 0) {
                   v = (0xff & yuv420sp[uvp++]) - 128;
                   u = (0xff & yuv420sp[uvp++]) - 128;
               }
               int y1192 = 1192 * y;
               int r = (y1192 + 1634 * v);
               int g = (y1192 - 833 * v - 400 * u);
               int b = (y1192 + 2066 * u);

               if (r < 0) r = 0; else if (r > 262143) r = 262143;
               if (g < 0) g = 0; else if (g > 262143) g = 262143;
               if (b < 0) b = 0; else if (b > 262143) b = 262143;

               rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
           }
       }
   }

}

